package org.zfes.snowier.cloud.zbss.metting.biz.service.impl;

import java.util.Date;
import java.util.Optional;
import java.util.Random;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.zfes.snowier.core.util.ZBeanUtil;
import org.zfes.snowier.core.util.ZDateUtil;
import org.zfes.snowier.core.util.ZValidateUtil;
import org.zfes.snowier.core.util.datex.ZDateStyle;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.zfes.snowier.core.util.AppCtxUtil;
import org.zfes.snowier.core.util.IPUtil;
import org.zfes.snowier.core.util.ZAlert;
import org.zfes.snowier.core.util.ZAssert;
import org.zfes.snowier.common.file.seaweed.http.okhttp3.OkHttpManager;
import org.zfes.snowier.cloud.zbss.metting.biz.service.IMemberService;
import org.zfes.snowier.cloud.zbss.metting.biz.service.ITenantMemberService;
import org.zfes.snowier.auth.biz.dto.AuthAccountDto;
import org.zfes.snowier.auth.biz.dto.AuthTenantCreateDto;
import org.zfes.snowier.auth.biz.model.AuthSmsVerify;
import org.zfes.snowier.auth.biz.model.AuthTenant;
import org.zfes.snowier.biz.factory.AuthManagerFactory;
import org.zfes.snowier.biz.manager.ISnowierSysAndAuthManager;
import org.zfes.snowier.cloud.zbss.metting.biz.MetBizConst;
import org.zfes.snowier.cloud.zbss.metting.biz.dto.acc.RegistDto;
import org.zfes.snowier.cloud.zbss.metting.biz.model.TenantMember;
@Service
public class MemberServiceImpl implements IMemberService{
	
	   private Logger log = LoggerFactory.getLogger(MemberServiceImpl.class);
	   @Autowired
	   ITenantMemberService tenantMemberService;
	   
	   protected ISnowierSysAndAuthManager authManager;
	   
		private ISnowierSysAndAuthManager getAuthManager() {
			if(authManager==null) {
				authManager=AppCtxUtil.cfg.getBean(AuthManagerFactory.class).getAuthManager();
			}
			return authManager;
		}
		
		
	    @Transactional(rollbackFor = Exception.class)
	    @Override
	    public void step1SendSmsCheckCode(String phone, String ip) {
	        log.debug("step1SendSmsCheckCode-||phone:" + phone + "||ip: " + ip);
	        ZAssert.hasText(phone, "手机号码错误");
	        ZAssert.isTrue(ZValidateUtil.isMobile(phone), "手机号格式不正确");

	        Optional<TenantMember> memberOp = tenantMemberService.loadByPhone(phone);
	        
	        log.debug("step1SendSmsCheckCode-||Member:" + memberOp.orElse(null));
	        memberOp.ifPresent(val -> ZAlert.serviceLogicalError("该手机号已注册"));

	        int expireTime = 91;//90s内只能发送一次

	        Date now = ZDateUtil.newDate();
	        log.debug("step1SendSmsCheckCode-||now:" + ZDateUtil.toString(now, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        // 时效内，只能发送一次
	        Optional<AuthSmsVerify> smsVerifyOp =  getAuthManager().loadLatestSmsVerifyByPhone(phone, Byte.valueOf("2"));
	        if(smsVerifyOp.isPresent()) {
	        	 boolean isInExpire = ZDateUtil.getIntervalSeconds(now,  smsVerifyOp.get().getExpireAt())>expireTime;
	        	 ZAssert.isTrue(isInExpire, "重复获取验证码，时间间隔不足["+expireTime+"]秒，请稍后重试");
	        }
	        long ipLong = IPUtil.ipStrToLong(ip);
	    
	        Date expireAt = ZDateUtil.addSecond(now, expireTime);
	        
	        log.debug("step1SendSmsCheckCode-||expireAt:" + ZDateUtil.toString(expireAt, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        
	        String checkCode = String.valueOf(new Random().nextInt(899999) + 100000);
	        log.debug("doStep1SendSmsCheckCode-||checkCode:" + checkCode);
	        try {
	        	//{"succ":"1"}
	            String smsContent= "您的注册验证码是【:"+checkCode+"】，请不要把验证码泄漏给其他人，如非本人请勿操作。【舜网】";
	            OkHttpManager.getInstance().getAsyncJson(smsContent, jsonResponse -> {
	            	 log.debug("step1SendSmsCheckCode-||发送结果:"+jsonResponse.getJson());
	            	 
	            	 JSONObject obj=(JSONObject)JSON.parse(jsonResponse.getJson());
	            	 ZAssert.equals("1", obj.getString("succ"), "短信发送失败，请稍后重试");
				});
	        } catch (Exception e) {
	            log.debug("step1SendSmsCheckCode-||发送失败:" + e.getMessage());
	            ZAlert.serviceLogicalError("短信发送异常,请稍后重试");
	        }
	        log.debug("step1SendSmsCheckCode-||发送成功:");
	 
	        getAuthManager().createAuthSmsVerify(new AuthSmsVerify( phone, checkCode,   ip,  ipLong,  now,  expireAt));
	        
	        
	    }
	
	    
	    
	    @Transactional(rollbackFor = Exception.class,readOnly=true)
	    @Override
	    public Long step2CheckSmsCode(String phone, String checkCode, String ip) {
	        log.debug("step2CheckSmsCode-||phone:" + phone + " checkCode:" + checkCode + " ip:" + ip);
	        ZAssert.hasText(checkCode, "请输入验证码");
	        ZAssert.hasText(phone, "手机号码错误");
	        ZAssert.isTrue(ZValidateUtil.isMobile(phone), "手机号格式不正确");

	        Date now = ZDateUtil.newDate();
	        log.debug("step2CheckSmsCode-||now:" + ZDateUtil.toString(now, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        
	        Optional<TenantMember> memberOp = tenantMemberService.loadByPhone(phone);
	        
	        log.debug("step2CheckSmsCode-||Member:" + memberOp.orElse(null));
	        memberOp.ifPresent(val -> ZAlert.serviceLogicalError("该手机号已注册"));
	        
	        
	        Optional<AuthSmsVerify> smsVerifyOp =  getAuthManager().loadLatestSmsVerifyByPhone(phone, Byte.valueOf("2"));
	        ZAssert.notEmpty(smsVerifyOp, "未查询到验证信息");
	   
	        ZAssert.isTrue(smsVerifyOp.get().getCheckCode().equals(checkCode), "验证码错误");
	        
	        boolean isNotExpired = ZDateUtil.isBefore(now, smsVerifyOp.get().getExpireAt());
	        
	        ZAssert.isTrue(isNotExpired, "验证码已超时");
	        ZAssert.isTrue(smsVerifyOp.get().getIp().equals(ip), "IP地址错误");

	        return smsVerifyOp.get().getId();

	    }
	    
	    

	    @Transactional(rollbackFor = Exception.class)
	    @Override
	    public Long step3CreateAccount(RegistDto registDto) {
	        log.debug("step3CreateAccount-||registDto:" + registDto + "||weichatOpenId:" + registDto.getWeichatOpenId());
	        ZBeanUtil.validateBean(registDto);
	        
	        ZAssert.hasText(registDto.getPassword(), "密码不能为空");
	        ZAssert.hasText(registDto.getPassword2(), "确认密码不能为空");
	        ZAssert.bigOrEqThanZero(registDto.getPassword().length()-3, "密码长度过短", "密码长度过短");
	        ZAssert.equals(registDto.getPassword(), registDto.getPassword2(), "密码不一致");
	        
	        AuthSmsVerify authSmsVerify= getAuthManager().loadSmsVerifyById(registDto.getSmsVerfyId()).orElseThrow(()-> ZAlert.newSLE("未查询到注册信息"));
	        
	        ZAssert.equals(authSmsVerify.getPhone(), registDto.getPhone(), "手机号不符，注册错误");
	        
	        ZAssert.equals(registDto.getPassword(), registDto.getPassword2(), "手机号不符，注册错误");

	        AuthAccountDto authAccountDto = AuthAccountDto.genWhithSep2(registDto.getAccount(),registDto.getPassword() ,MetBizConst.ROLE_MEMBER);
	        authAccountDto.setAuthLevel(2);
	        
	        Long userId=getAuthManager().createAccount(authAccountDto);
	        
	        TenantMember tenantMember=new TenantMember(userId);
	        ZBeanUtil.copy(registDto, tenantMember, true);
	        
	        tenantMemberService.createTenantMember(tenantMember);
	   
	        log.debug("doStep3CreateMemberAccount-||over:");
	        return userId;
	    }
	    
	    
	//=====================================================================================    
	    
	    @Transactional(rollbackFor = Exception.class)
	    @Override
	    public void chengePwdSendSmsCheckCode(String phone, String ip) {
	        log.debug("chengePwdSendSmsCheckCode-||phone:" + phone + "||ip: " + ip);
	        ZAssert.hasText(phone, "手机号码错误");
	        ZAssert.isTrue(ZValidateUtil.isMobile(phone), "手机号格式不正确");

	        Optional<TenantMember> memberOp = tenantMemberService.loadByPhone(phone);
	        
	        log.debug("chengePwdSendSmsCheckCode-||Member:" + memberOp.orElse(null));
	        memberOp.ifPresent(val -> ZAlert.serviceLogicalError("该手机号已注册"));

	        int expireTime = 60*5;//90s内只能发送一次

	        Date now = ZDateUtil.newDate();
	        log.debug("chengePwdSendSmsCheckCode-||now:" + ZDateUtil.toString(now, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        // 时效内，只能发送一次
	        Optional<AuthSmsVerify> smsVerifyOp =  getAuthManager().loadLatestSmsVerifyByPhone(phone, Byte.valueOf("2"));
	        if(smsVerifyOp.isPresent()) {
	        	 boolean isInExpire = ZDateUtil.getIntervalSeconds(now,  smsVerifyOp.get().getExpireAt())>expireTime;
	        	 ZAssert.isTrue(isInExpire, "重复获取验证码，时间间隔不足["+expireTime+"]秒，请稍后重试");
	        }
	        long ipLong = IPUtil.ipStrToLong(ip);
	    
	        Date expireAt = ZDateUtil.addSecond(now, expireTime);
	        
	        log.debug("chengePwdSendSmsCheckCode-||expireAt:" + ZDateUtil.toString(expireAt, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        
	        String checkCode = String.valueOf(new Random().nextInt(899999) + 100000);
	        log.debug("chengePwdSendSmsCheckCode-||checkCode:" + checkCode);
	        try {
	        	//{"succ":"1"}
	            String smsContent= "您的注册验证码是【:"+checkCode+"】，请不要把验证码泄漏给其他人，如非本人请勿操作。【舜网】";
	            OkHttpManager.getInstance().getAsyncJson(smsContent, jsonResponse -> {
	            	 log.debug("chengePwdSendSmsCheckCode-||发送结果:"+jsonResponse.getJson());
	            	 
	            	 JSONObject obj=(JSONObject)JSON.parse(jsonResponse.getJson());
	            	 ZAssert.equals("1", obj.getString("succ"), "短信发送失败，请稍后重试");
				});
	        } catch (Exception e) {
	            log.debug("chengePwdSendSmsCheckCode-||发送失败:" + e.getMessage());
	            ZAlert.serviceLogicalError("短信发送异常,请稍后重试");
	        }
	        log.debug("chengePwdSendSmsCheckCode-||发送成功:");
	 
	        getAuthManager().createAuthSmsVerify(new AuthSmsVerify( phone, checkCode,   ip,  ipLong,  now,  expireAt));
	        
	        
	    }
	    
	    @Transactional(rollbackFor = Exception.class,readOnly=false)
	    @Override
	    public void chengePwdDoSet(String phone, String checkCode, String ip,String password,String password2) {
	        log.debug("chengePwdDoSet-||phone:" + phone + " checkCode:" + checkCode + " ip:" + ip);
	        ZAssert.hasText(checkCode, "请输入验证码");
	        ZAssert.hasText(phone, "手机号码错误");
	        ZAssert.hasText(password, "密码不能为空");
	        ZAssert.hasText(password2, "确认密码不能为空");
	        ZAssert.bigOrEqThanZero(password.length()-3, "密码长度过短", "密码长度过短");
	        ZAssert.equals(password, password, "密码不一致");
	        ZAssert.isTrue(ZValidateUtil.isMobile(phone), "手机号格式不正确");

	        Date now = ZDateUtil.newDate();
	        log.debug("step2CheckSmsCode-||now:" + ZDateUtil.toString(now, ZDateStyle.YYYY_MM_DD_HH_MM_SS));
	        
	        Optional<TenantMember> memberOp = tenantMemberService.loadByPhone(phone);
	        ZAssert.notEmpty(memberOp, "手机号未注册");
	        
	        
	        Optional<AuthSmsVerify> smsVerifyOp =  getAuthManager().loadLatestSmsVerifyByPhone(phone, Byte.valueOf("3"));
	        ZAssert.notEmpty(smsVerifyOp, "未查询到验证信息");
	   
	        ZAssert.isTrue(smsVerifyOp.get().getCheckCode().equals(checkCode), "验证码错误");
	        
	        boolean isNotExpired = ZDateUtil.isBefore(now, smsVerifyOp.get().getExpireAt());
	        
	        ZAssert.isTrue(isNotExpired, "验证码已超时");
	        ZAssert.isTrue(smsVerifyOp.get().getIp().equals(ip), "IP地址错误");
	        
	        getAuthManager().setAuthUserPwd(memberOp.get().getId(), password);

	    }
	    
	    
	    @Transactional(rollbackFor = Exception.class,readOnly=true)
	    @Override
	    public Optional<TenantMember> loadTenantMemberByUserId(Long userId) {
	    	
	    	Optional<TenantMember> memberOp = tenantMemberService.loadTenantMemberById(userId);
	    
	    	return memberOp;
	    }
	    	
	    	
	    
	    
	    @Transactional(rollbackFor = Exception.class,readOnly=true)
	    @Override
	    public Long openTenant(Long userId) {
	    	
	    	Optional<AuthTenant>  tenantOp=getAuthManager().loadTenantByAuthorId(userId);
	    	if(tenantOp.isPresent()&&Byte.valueOf("2").equals(tenantOp.get().getStatus())) {
	    		return tenantOp.get().getId();
	    	}
	    	AuthTenantCreateDto authTenant=new AuthTenantCreateDto();
	    	authTenant.setAuthorId(userId);
	    	if(MetBizConst.TENANT_NEED_CHECK) {
	    		//状态_D#0未申请，初始状态 1申请，2 审核通过，3审核未通过， 4注销#
		    	authTenant.setStatus(Byte.valueOf("1"));
	    	}else {
	    		authTenant.setStatus(Byte.valueOf("2"));
	    	}
	    	
	    	Long tenantId= getAuthManager().createAuthTenant(authTenant);
	    	return tenantId;
	    }
	    
	
}